package org.sgx.jsutil.client.appstate;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.sgx.jsutil.client.JsUtil;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;

/**
 * @author sg
 * 
 */
public abstract class AbstractAppStateManager implements AppStateManager {

	Map<String, AppState> states;

	// List<StateListener> listeners;

	public AbstractAppStateManager() {
		// listeners = new LinkedList<StateListener>();
		states = new HashMap<String, AppState>();
		registerForHistoryEvents();
	}

	@Override
	public AppState getNotFoundState() {
		// TODO Auto-generated method stub
		return null;
	}

	public void navigate(AppState state, String params) {
		String historyToken = getHistoryPrefix() + state.getName() + getParamSeparator() + params;
		// System.out.println("navigate: "+historyToken);

		History.newItem(historyToken);
		// notifyAllStateListeners();
	}

	public void navigate(String stateName, String params) {
		// System.out.println("navigate: "+stateName+", "+params);
		navigate(getStates().get(stateName), params);
	}

	protected void registerForHistoryEvents() {
		History.addValueChangeHandler(new ValueChangeHandler<String>() {
			public void onValueChange(ValueChangeEvent<String> event) {
				String historyToken = event.getValue();
				// System.out.println("registerForHistoryEvents 0 "+event.getAssociatedType()+" - "+event.getValue());
				if (historyToken != null && historyToken.startsWith(getHistoryPrefix())) {
					AppState state = searchStateInHistoryToken(historyToken);
					String params = searchStateParamsInHistoryToken(historyToken);
					dispatch(state, params);

				} else {
					// System.out.println("registerForHistoryEvents 2 : "+historyToken);
					// getDefaultState().perform(null);
				}
			}
		});
	}

	protected void dispatch(AppState state, String params) {
		// System.out.println("registerForHistoryEvents 1 : "+historyToken+" - "+state.getName()+" - "+params);
		if (state != null) {
			state.perform(params);
		} else {
			getNotFoundState().perform(null);
		}
	}

	protected String getHistoryPrefix() {
		return "page";
	}

	protected String getParamSeparator() {
		return "/";
	}

	protected AppState searchStateInHistoryToken(String historyToken) {
		for (String stateName : getStates().keySet()) {
			if (historyToken.contains(stateName)) {
				return getStates().get(stateName);
			}
		}
		return null;
	}

	protected String searchStateParamsInHistoryToken(String historyToken) {
		int index = historyToken.lastIndexOf(getHistoryPrefix());
		String s = historyToken.substring(index + getHistoryPrefix().length(), historyToken.length());
		index = s.indexOf(getParamSeparator());
		if (index == -1)
			return null;
		else
			return s.substring(index + 1, s.length());
	}

	public Map<String, AppState> getStates() {
		return states;
	}

	public static interface ModuleLoadedListener {
		void loaded(String name);
	}

	// protected void notifyAllStateListeners() {
	// for (StateListener l : listeners) {
	// l.notifyStateChange(this);
	// }
	// }

	/**
	 * gets the state name from url. if not state is found returns null.
	 * 
	 * @param url
	 * @return
	 */
	public String urlContainsState(String url) {
		int i = url.lastIndexOf("#");
		if (i > 0) {
			String historyToken = null;
			try {
				historyToken = url.substring(i + 1, url.length());
			} catch (Exception e) {
			}
			AppState state = searchStateInHistoryToken(historyToken);
			if (state == null)
				return null;
			else
				return state.getName();
		}
		return null;
	}

	// @Override
	// public void addStateListener(StateListener l) {
	// listeners.add(l);
	// }
	//
	// @Override
	// public void removeStateListener(StateListener l) {
	// listeners.remove(l);
	// }

	public void addState(AppState s) {
		states.put(s.getName(), s);
	}

}
